home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp48_2 / areuh.tar / areuh / msg / amg.c < prev    next >
C/C++ Source or Header  |  1990-10-10  |  17KB  |  668 lines

  1. /*
  2.  * Authors :
  3.  *   Pierre DAVID (pda@masi.ibp.fr or pda@frunip62.bitnet)
  4.  *   Janick TAILLANDIER
  5.  *
  6.  * This program can be freely used or distributed as long as this
  7.  * note is kept.
  8.  *
  9.  * This program is provided "as is".
  10.  */
  11.  
  12. #include <stdio.h>            /* Pour emmerder J.T. */
  13.  
  14. #define EOL '\0'            /* End Of Line */
  15. #define NSTR ""                /* null string */
  16. #define SPEC_CHAR '\\'            /* special character */
  17. #define MAXLEN 500            /* input line max length */
  18. #define MSGLEN 48            /* message max length */
  19. #define LBLMAX 7            /* length of a sasm label */
  20.  
  21. #define BBMAX    64            /* max number of building blocks */
  22. #define MGMAX    255            /* max number of messages         */
  23.  
  24. #define ERRUSA    1            /* usage: msg in_file out_file [n] */
  25. #define ERRINP    2            /* invalid input line */
  26. #define ERRIVL    3            /* invalid building block */
  27. #define ERRTMB    4            /* too many blocks */
  28. #define ERRTMM    5            /* too many messages */
  29. #define ERRNSB    6            /* no sufficient space for blocks */
  30. #define ERRFST    7            /* no valid first message */
  31.  
  32.  
  33. #define VALUE(p) ((p)&((token)0xff))/* value of a token */
  34. #define MFBB (token) 0x100        /* MainFrame Building Block */
  35. #define LLBB (token) 0x200        /* LocaL Building Block */
  36. #define ASCH (token) 0x400        /* AScii CHaracter */
  37. #define INST (token) 0x800        /* INSerTion mark */
  38.  
  39. typedef short int token ;        /* token = (type, value)  */
  40.  
  41. /* ascii representations of messages / building blocks */
  42.  
  43. char mftab[17][MSGLEN+1] ;        /* mainframe building blocks */
  44. char bbtab[BBMAX][MSGLEN+1] ;        /* local building blocks table */
  45. char mgtab[MGMAX][MSGLEN+1] ;        /* message table */
  46.  
  47. /* tokenised representations for local messages / building blocks */
  48. token bbtok[BBMAX][MSGLEN+1] ;        /* local building blocks */
  49. token mgtok[MGMAX][MSGLEN+1] ;        /* messages */
  50.  
  51. /* length of local messages / building blocks */
  52. short int bblen[BBMAX] ;
  53. short int mglen[MGMAX] ;
  54.  
  55. /* symbolic labels for messages */
  56. char lbltab[MGMAX][LBLMAX+1] ;
  57.  
  58. int mbase = 0 ;      /* base for message numerotation */
  59. int bbase ;      /* base for building block numerotation */
  60.  
  61. int mdep ;      /* relative message number (relative to mbase) */
  62. int bdep ;      /* idem for building blocks */
  63.  
  64. char line [MAXLEN+1] ;            /* input line */
  65. char *pline ;
  66.  
  67. int ln = 0 ;                /* line number */
  68.  
  69. int ind16 ;                /* msg # whose length is 16, 32, 48... */
  70. #define INMG 0x100            /* msg in mgtab */
  71. #define INBB 0x200            /* msg in bbtab */
  72.  
  73. token read_block () ;
  74.  
  75.  
  76. /******************************************************************************
  77.                      MAIN
  78.  
  79. purpose : main program. see called procedures for information.
  80. ******************************************************************************/
  81. main (argc, argv)
  82. int argc ;
  83. char *argv[] ;
  84. {
  85.     if (argc>2) erreur(ERRUSA) ;
  86.     else if (argc==2) mbase = atoi(argv[1]) ;
  87.  
  88.     init () ;
  89.     pass1 () ;
  90.     between () ;
  91.     pass2 () ;
  92.     exit (0) ;
  93. }
  94.  
  95.  
  96. /******************************************************************************
  97.                      INIT
  98.  
  99. purpose : initializes "mainframe building blocks" list.
  100. ******************************************************************************/
  101. init ()
  102. {
  103.     strcpy (mftab [0], "Illegal ") ;
  104.     strcpy (mftab [1], " Expected") ;
  105.     strcpy (mftab [2], " Not Found") ;
  106.     strcpy (mftab [3], "Context") ;
  107.     strcpy (mftab [4], "File") ;
  108.     strcpy (mftab [5], " w/o ") ;
  109.     strcpy (mftab [6], "Invalid ") ;
  110.     strcpy (mftab [7], "Stat") ;
  111.     strcpy (mftab [8], "Too ") ;
  112.     strcpy (mftab [9], ": Align then ENDLN") ;
  113.     strcpy (mftab[10], "Transform") ;
  114.     strcpy (mftab[11], "Inf") ;
  115.     strcpy (mftab[12], " Input") ;
  116.     strcpy (mftab[13], " Ovfl") ;
  117.     strcpy (mftab[14], "Pull") ;
  118.     strcpy (mftab[15], "") ;         /* insert message : ### of ### */
  119.     strcpy (mftab[16], " Protect") ;
  120. }
  121.  
  122.  
  123. /******************************************************************************
  124.                 READ_LINE
  125.  
  126. synopsis : int read_line ()
  127. description : reads a line from stdin
  128. note : returns -1 if EOF reached, 0 otherwise
  129. ******************************************************************************/
  130. int read_line ()
  131. {
  132.     int c, i = -1 ;
  133.  
  134.     ln++ ;            /* new line to be read */
  135.     do
  136.     {
  137.     c = getchar () ;
  138.     if (i<MAXLEN) line[++i] = (char) c ;
  139.     }
  140.     while ((c!=EOF)&&(c!='\n')) ;
  141.     line [i] = EOL ;
  142.     return ( (c==EOF) ? -1 : 0) ;
  143. }
  144.  
  145.  
  146. /******************************************************************************
  147.                  BUILD_LABEL
  148.  
  149. purpose : scans the line, isolate the label if exits, otherwise generates it.
  150. ******************************************************************************/
  151. build_label ()
  152. {
  153.     int i = 0 ;
  154.  
  155.     while ((*pline!=':')&&(*pline!=EOL))
  156.     {
  157.     if (i<LBLMAX) lbltab [mdep][i++] = *pline ;
  158.     pline++ ;
  159.     }
  160.     if (*pline==EOL) erreur (ERRINP) ;
  161.     pline++ ;
  162.     if (i) lbltab [mdep][i] = EOL ;
  163.     else sprintf (lbltab[mdep], "MSG%d", mbase + mdep) ;
  164. }
  165.  
  166.  
  167. /******************************************************************************
  168.                  GET_CODE
  169.  
  170. synopsis : get_code ()
  171. purpose : parses a number if possible (three digits < 256), and modify input
  172.   line and its pointer (line/pline). If not possible, returns pline unchanged.
  173. ******************************************************************************/
  174. void get_code ()
  175. {
  176.     register char *pp ;
  177.     register int code ;
  178.  
  179.     pp = pline ;
  180.     code = (*(pp++)-'0') * 100 ;
  181.     if ((*pp<'0') || (*pp>'9')) return ;
  182.     code += (*(pp++)-'0') * 10 ;
  183.     if ((*pp<'0') || (*pp>'9')) return ;
  184.     code += (*pp)-'0' ;
  185.     if (code>255) return ;
  186.     pline = pp ;
  187.     *pline = (char)code ;
  188.     return ;
  189. }
  190.  
  191.  
  192. /******************************************************************************
  193.                    PASS1
  194.  
  195. synopsis : pass1 ()
  196. purpose : reads stdin and, for each line, parses it, creates local building
  197.   blocks if any, and tokenises the message.
  198. ******************************************************************************/
  199. pass1 ()
  200. {
  201.     int itok, ncar, iascii ;
  202.     token bb ;
  203.  
  204.     mdep = 0 ;
  205.     bdep = 0 ;
  206.     while (read_line () == 0)
  207.     {
  208.     pline = line ;
  209.     build_label () ;
  210.     mglen [mdep] = 4 + 1 ;     /* 4 for (blk len, msg #), 1 for blk term. */
  211.     itok = 0 ;
  212.     ncar = 0 ;
  213.     iascii = 0 ;
  214.     while (*pline)
  215.     {
  216.         switch (*pline)
  217.         {
  218.         case '^' :        /* insert text cell */
  219.             if (*(pline+1)==' ')
  220.             {
  221.             pline++ ;       /* trailing space */
  222.             mgtok [mdep][itok++] = INST + 0xf3 ;
  223.             }
  224.             else
  225.             mgtok [mdep][itok++] = INST + 0xf2 ;
  226.             mgtab [mdep][iascii++] = '^' ;
  227.             mglen [mdep] += 2 ;
  228.             ncar = 0 ;
  229.             break ;
  230.         case '[' :
  231.             pline++ ;
  232.             bb = read_block () ;     /* bb  is a full token */
  233.             mgtok [mdep][itok++] = bb ;
  234.             mgtab [mdep][iascii] = EOL ;
  235.             strcat (mgtab[mdep], (bb&MFBB) ? mftab [VALUE(bb)-230]
  236.                            : bbtab [VALUE(bb)] ) ;
  237.             iascii = strlen (mgtab[mdep]) ;
  238.             mglen [mdep] += 3 ;
  239.             ncar = 0 ;
  240.             break ;
  241.         case SPEC_CHAR :
  242.             pline++ ;
  243.             if (*pline==EOL) break ;
  244.             if ((*pline=='0')||(*pline=='1')||(*pline=='2'))
  245.             get_code () ;
  246.         default :
  247.             if (ncar == 0 ) mglen[mdep] ++ ;
  248.             ncar++ ;
  249.             mgtab [mdep][iascii++] = *pline ;
  250.             mgtok [mdep][itok++] = ASCH + (unsigned char) *pline ;
  251.             mglen [mdep] += 2 ;
  252.             if (ncar == 12) mglen [mdep] ++ ; /* cell > 11 char */
  253.             else if (ncar == 17)
  254.             {
  255.             ncar = 1 ;
  256.             mglen [mdep] ++ ;
  257.             }
  258.             break ;
  259.         }
  260.         pline++ ;
  261.     }
  262.     mgtab[mdep][iascii] = EOL ;
  263.     mdep++ ;
  264.     if (mdep>MGMAX) erreur (ERRTMM) ;
  265.     }
  266. }
  267.  
  268.  
  269. /******************************************************************************
  270.                   READ_BLOCK
  271.  
  272. synopsis : token read_block ()
  273. purpose : reads a block in input line, finds it if already defined. Otherwise
  274.   stores it in block tables. Returns a complete token.
  275. ******************************************************************************/
  276. token read_block ()
  277. {
  278.     int iascii = 0 ;
  279.     int ncar = 0 ;
  280.     int x, itok = 0 ;
  281.  
  282.     bblen [bdep] = 5 ;
  283.     while ((*pline)&&(*pline!=']'))
  284.     {
  285.     if (*pline==SPEC_CHAR)
  286.     {
  287.         pline++ ;
  288.         if (*pline==EOL) break ;
  289.         if ((*pline=='0')||(*pline=='1')||(*pline=='2'))
  290.         get_code () ;
  291.     }
  292.     if (*pline==EOL) erreur (ERRIVL) ;
  293.     if (ncar==0) bblen [bdep] ++ ;
  294.     ncar++ ;
  295.     bbtab [bdep][iascii++] = *pline ;
  296.     bbtok [bdep][itok++] = ASCH + (unsigned char) *pline ;
  297.     bblen [bdep] += 2 ;
  298.     if (ncar == 12) bblen [bdep]++ ;
  299.     else if (ncar == 17)
  300.     {
  301.         ncar = 1 ;
  302.         bblen [bdep]++ ;
  303.     }
  304.     pline++ ;
  305.     }
  306.     if (*pline==EOL) erreur (ERRIVL) ;
  307.     bbtab [bdep][iascii] = EOL ;
  308.     bbtok [bdep][itok] = (token) 0 ;
  309.     x = find_block (bbtab[bdep], mftab, 16) ;
  310.     if (x>=0) return ((token)(MFBB + x + 230)) ;
  311.     x = find_block (bbtab[bdep], bbtab, bdep-1) ;
  312.     if (x>=0) return ((token)(LLBB + x)) ;
  313.     if (bdep>=BBMAX) erreur (ERRTMB) ;
  314.     return ((token)(LLBB + bdep++)) ;
  315. }
  316.  
  317.  
  318. /******************************************************************************
  319.                  FIND_BLOCK
  320.  
  321. synopsis : int find_block (areuh, tab, imax)
  322.        char *areuh ;
  323.        char tab [][MSGLEN+1] ;
  324.        int imax ;
  325. purpose : searches in table tab (mainframe / local building blocks) for 
  326.   areuh building block. If found, return its index, otherwise -1.
  327. ******************************************************************************/
  328. int find_block (areuh, tab, imax)
  329. char *areuh ;
  330. char tab[][MSGLEN+1] ;
  331. int imax ;
  332. {
  333.     int i ;
  334.  
  335.     for (i=0; i<=imax; i++)
  336.     if (strcmp (tab[i], areuh)==0) return (i) ;
  337.     return (-1) ;
  338. }
  339.  
  340.  
  341. /******************************************************************************
  342.                    FIND_16
  343.  
  344. synopsis : int find_16 (xxlen, dep)
  345.        short int xxlen[] ;
  346.        int dep ;
  347. description : returns the index of a message whose length is a multiple of 16,
  348.   otherwise -1.
  349. ******************************************************************************/
  350. int find_16 (xxlen, dep)
  351. short int xxlen[] ;
  352. int dep ;
  353. {
  354.     int i = 0 ;
  355.  
  356.     while (i<dep)
  357.     if (xxlen[i] % 16) i++ ;
  358.     else break ;
  359.     return ((i==dep) ? -1 : i) ;
  360. }
  361.  
  362.  
  363. /******************************************************************************
  364.                    BETWEEN
  365.  
  366. synopsis : between ()
  367. purpose : find a message length multiple of 16. If no one, then disp an error
  368.   message and build a comment.
  369.   Caclulate base for building blocks.
  370. ******************************************************************************/
  371. between ()
  372. {
  373.     ind16 = find_16 (mglen, mdep) ;
  374.     if (ind16>=0)
  375.     ind16 += INMG ;
  376.     else
  377.     {
  378.     ind16 = find_16 (bblen, bdep) ;
  379.     if (ind16>=0)
  380.         ind16 += INBB ;
  381.     else
  382.     {
  383.         ind16 = 0 ;
  384.         printf ("**************************\n") ;
  385.         printf ("* E R R O R        ! ! ! *\n") ;
  386.         printf ("*                        *\n") ;
  387.         printf ("* no valid first message *\n") ;
  388.         printf ("**************************\n") ;
  389.     }
  390.     }
  391.     if (mbase + mdep + bdep - 1 <= 255)
  392.     bbase = mbase + mdep ;
  393.     else
  394.     {
  395.     if (bdep < mbase)
  396.         bbase = 0 ;
  397.     else erreur (ERRNSB) ; /* no sufficient space for blocks */
  398.     }
  399. }
  400.  
  401.  
  402. /******************************************************************************
  403.                      PASS2
  404.  
  405. synopsis : pass2 ()
  406. purpose : sends output to stdout.
  407. ******************************************************************************/
  408. pass2 ()
  409. {
  410.     int index ;
  411.  
  412.     header () ;
  413.  
  414.     index = ind16 & ~(INMG | INBB) ;
  415.     switch (ind16 & (INMG | INBB))
  416.     {
  417.     case INMG :
  418.         print_msg (mgtab, mgtok, mglen, index) ;
  419.         break ;
  420.     case INBB :
  421.         print_msg (bbtab, bbtok, bblen, index) ;
  422.         break ;
  423. /*    default :    there is no valid first message */
  424.     }
  425.  
  426.     if (ind16 & INMG)
  427.     {
  428.     build (mgtab, mgtok, mglen, 0, index - 1) ;
  429.     build (mgtab, mgtok, mglen, index + 1, mdep - 1) ;
  430.     }
  431.     else build (mgtab, mgtok, mglen, 0, mdep - 1) ;
  432.  
  433.     if (ind16 & INBB)
  434.     {
  435.     build (bbtab, bbtok, bblen, 0, index - 1) ;
  436.     build (bbtab, bbtok, bblen, index + 1, bdep - 1) ;
  437.     }
  438.     else build (bbtab, bbtok, bblen, 0, bdep - 1) ;
  439.  
  440.     terminator () ;
  441. }
  442.  
  443.  
  444. /******************************************************************************
  445.                    PRINT_MSG
  446.  
  447. synopsis : print_msg (tab, tok, len, ind)
  448.        char tab [][MSGLEN+1] ;
  449.        token tok [][MSGLEN+1] ;
  450.        short int len [] ;
  451.        int ind ;
  452. purpose : outputs message ind in table (tab, tok, len).
  453. ******************************************************************************/
  454. print_msg (tab, tok, len, ind)
  455. char tab [][MSGLEN+1] ;
  456. token tok [][MSGLEN+1] ;
  457. short int len [] ;
  458. int ind ;
  459. {
  460.     token c ;
  461.     int msg, j, k ;
  462.     char areuh [MAXLEN] ;
  463.  
  464.     msg = ((tab==mgtab) ? 1 : 0) ;
  465.     printf ("\n") ;
  466.     printf ("* %s\n", tab[ind]) ;    /* message text */
  467.     printf ("%8sCON(2) %d\n", NSTR, len[ind]) ;          /* length */
  468.  
  469.     printf ("%8sCON(2) ", NSTR) ;
  470.     if (msg) printf ("%-7s", lbltab [ind]) ;
  471.     else printf ("BB%-3d  ", bbase + ind ) ;
  472.     printf ("  Message # %d\n", ((msg) ? mbase : bbase) + ind) ;
  473.  
  474.     j = 0 ;
  475.     while (tok[ind][j])
  476.     {
  477.     switch ((tok[ind][j]) & (MFBB | LLBB | ASCH | INST) )
  478.     {
  479.         case (int)MFBB :
  480.         printf ("%8sCON(1) 14\n", NSTR) ;
  481.         printf ("%8sCON(2) %d\n", NSTR, VALUE(tok[ind][j])) ;
  482.         j++ ;
  483.         break ;
  484.         case (int)LLBB :
  485.         printf ("%8sCON(1) 13\n", NSTR) ;
  486.         printf ("%8sCON(2) BB%d\n", NSTR, bbase + VALUE(tok[ind][j])) ;
  487.         j++ ;
  488.         break ;
  489.         case (int)INST :
  490.         printf ("%8sNIBHEX %2x\n", NSTR, VALUE(tok[ind][j])) ;
  491.         j++ ;
  492.         break ;
  493.         case (int)ASCH :
  494.         k = 0 ;
  495.         while (((c=tok[ind][j+k])&ASCH) && (k<16))
  496.             areuh [k++] = VALUE (c) ;
  497.         areuh [k] = EOL ;
  498.         if (k<=8)
  499.         {
  500.             printf ("%8sCON(1) %d\n", NSTR, k-1) ;
  501.             output_ascii (areuh, k) ;
  502.         }
  503.         else if (k<=11)
  504.         {
  505.             printf ("%8sCON(1) %d\n", NSTR, k-1) ;
  506.             output_ascii (areuh, 8) ;
  507.             output_ascii (areuh+8, k-8) ;
  508.         }
  509.         else
  510.         {
  511.             printf ("%8sCON(1) 11\n", NSTR) ;
  512.             printf ("%8sCON(1) %d\n", NSTR, k-1) ;
  513.             output_ascii (areuh, 8) ;
  514.             output_ascii (areuh+8, k-8) ;
  515.         }
  516.         j += k ;
  517.     }
  518.     }
  519.     printf ("%8sCON(1) 12\n", NSTR) ;
  520. }
  521.  
  522.  
  523. /******************************************************************************
  524.                   OUTPUT_ASCII
  525.  
  526. synopsis : output_ascii (str, len)
  527.        char *str ;
  528.        int len ;
  529. purpose : outputs a string in sasm format (NIBASC / CON()), depending on the
  530.   ascii value of characters.
  531. ******************************************************************************/
  532. output_ascii (str, len)
  533. unsigned char *str ;
  534. int len ;
  535. {
  536.     char buf[MAXLEN] ;
  537.     char *pbuf ;
  538.  
  539.     pbuf = buf ;
  540.     while (len--)
  541.     {
  542.     if ((*str >= 0x20) && (*str <= 0x7e) && (*str != '\''))
  543.     {
  544.         *pbuf = *str ;
  545.         pbuf++ ;
  546.     }
  547.     else
  548.     {
  549.         if (pbuf != buf)
  550.         {
  551.         *pbuf = EOL ;
  552.         printf ("%8sNIBASC '%s'\n", NSTR, buf) ;
  553.         pbuf = buf ;
  554.         }
  555.         printf ("%8sCON(2) %d\n", NSTR, *str) ;
  556.     }
  557.     str++ ;
  558.     }
  559.     if (pbuf != buf)
  560.     {
  561.     *pbuf = EOL ;
  562.     printf ("%8sNIBASC '%s'\n", NSTR, buf) ;
  563.     }
  564. }
  565.  
  566.  
  567. /******************************************************************************
  568.                     BUILD
  569.  
  570. synospis : build (tab, tok, len, n1, n2)
  571.        char tab [][MSGLEN+1] ;
  572.        token tok [][MSGLEN+1] ;
  573.        short int len [] ;
  574.        int n1, n2 ;
  575. purpose : build a list of messages.
  576. ******************************************************************************/
  577. build (tab, tok, len, n1, n2)
  578. char tab [][MSGLEN+1] ;
  579. token tok [][MSGLEN+1] ;
  580. short int len [] ;
  581. int n1, n2 ;
  582. {
  583.     int i ;
  584.  
  585.     for (i=n1; i<=n2; i++)
  586.     print_msg (tab, tok, len, i) ;
  587. }
  588.  
  589.  
  590. /******************************************************************************
  591.                    HEADER
  592.  
  593. synopsis : header ()
  594. purpose : print table header, cad EQU table, lowest and highest msg #.
  595. ******************************************************************************/
  596. header ()
  597. {
  598.     int i ;
  599.  
  600.     printf ("MBASE   EQU    %d\n", mbase) ;
  601.     for (i=0; i<mdep; i++)
  602.     printf ("%-7s EQU    (MBASE)+%-3d  %s\n", lbltab[i], i, mgtab[i]) ;
  603.  
  604.     if (bdep)
  605.     {
  606.     printf ("\n") ;
  607.     for (i=0; i<bdep; i++)
  608.         printf ("BB%-3d   EQU    %-11d  %s\n",
  609.         bbase + i, bbase + i, mgtab[i]) ;
  610.     }
  611.  
  612.     printf ("\n") ;
  613.     printf ("=MSGTBL\n") ;
  614.     printf ("%8sCON(2) (MBASE)+0    Lowest message #\n", NSTR) ;
  615.     printf ("%8sCON(2) (MBASE)+%-3d  Highest message #\n", NSTR, mdep-1) ;
  616. }
  617.  
  618.  
  619. /******************************************************************************
  620.                    TERMINATOR
  621.  
  622. synospsis : terminator ()
  623. purpose : print "NIBHEX FF"
  624. ******************************************************************************/
  625. terminator ()
  626. {
  627.     printf ("\n") ;
  628.     printf ("%8sNIBHEX FF       Table terminator\n", NSTR);
  629.     if (ind16==0) erreur (ERRFST) ;
  630. }
  631.  
  632.  
  633. /******************************************************************************
  634.                 ERREUR
  635.  
  636. synopsis : erreur (errn)
  637. purpose : declenche une erreur de numero errn
  638. ******************************************************************************/
  639. erreur (errn)
  640. {
  641.     fprintf (stderr, "amg: error in line %d, ", ln) ;
  642.     switch (errn)
  643.     {
  644.     case ERRUSA :
  645.         fprintf (stderr, "usage: amg [n]\n") ;
  646.         break ;
  647.     case ERRINP :
  648.         fprintf (stderr, "invalid source line\n") ;
  649.         break ;
  650.     case ERRIVL :
  651.         fprintf (stderr, "invalid building block\n") ;
  652.         break ;
  653.     case ERRTMB :
  654.         fprintf (stderr, "too many blocks\n") ;
  655.         break ;
  656.     case ERRTMM :
  657.         fprintf (stderr, "too many messages\n") ;
  658.         break ;
  659.     case ERRNSB :
  660.         fprintf (stderr, "not enough space for blocks\n") ;
  661.         break ;
  662.     case ERRFST :
  663.         fprintf (stderr, "no valid first message\n") ;
  664.         break ;
  665.     }
  666.     exit(2) ;
  667. }
  668.